package token

import (
	"fmt"
	"strconv"
)

type Token struct {
	Type    TokenType
	Literal []rune
}

type TokenType int

const (
	ILLEGAL TokenType = iota
	EOF
	COMMENT

	TK_设 // let
	TK_令 // var
	TK_为 // =

	literal_beg
	TK_名称
	TK_数
	TK_浮点数
	TK_布尔
	literal_end

	operator_beg

	TK_左方 // 【
	TK_右方 // 】
	TK_冒号 // ：
	TK_句号 // 。

	ADD    // +
	SUB    // -
	MUL    // *
	QUO    // /
	ASSIGN // =
	LSS    // <
	GTR    // >
	NOT    // !

	ADD_ASSIGN // +=
	SUB_ASSIGN // -=
	MUL_ASSIGN // *=
	QUO_ASSIGN // /=

	EQL     // ==
	LSS_EQL // <=
	GTR_EQL // >=
	NOT_EQL // !=

	LAND // !!
	LOR  // ||

	LPAREN // (
	LBRACK // [
	LBRACE // {
	COMMA
	PERIOD

	RPAREN
	RBRACK
	RBRACE
	SEMICOLON
	COLON

	operator_end

	keyword_beg
	// keywords
	ELSE
	FOR
	FN

	IF
	RETURN
	VAR

	TK_若
	TK_则
	TK_否则

	keword_end
)

var tokens = [...]string{
	ILLEGAL: "illegal",

	EOF:     "eof",
	COMMENT: "comment",

	TK_令: "令",
	TK_为: "为",

	TK_名称:  "ident",
	TK_数:   "int",
	TK_浮点数: "float",
	TK_布尔:  "bool",

	TK_左方: "【",
	TK_右方: "】",
	TK_冒号: "：",
	TK_句号: "。",

	ADD:    "+",
	SUB:    "-",
	MUL:    "*",
	QUO:    "/",
	ASSIGN: "=",
	LSS:    "<",
	GTR:    ">",
	NOT:    "!",

	ADD_ASSIGN: "+=",
	SUB_ASSIGN: "-=",
	MUL_ASSIGN: "*=",
	QUO_ASSIGN: "/=",

	EQL:     "==",
	LSS_EQL: "<=",
	GTR_EQL: ">=",
	NOT_EQL: "!=",

	LAND: "&&",
	LOR:  "||",

	LPAREN: "(",
	LBRACK: "[",
	LBRACE: "{",
	COMMA:  ",",
	PERIOD: ".",

	RPAREN:    ")",
	RBRACK:    "]",
	RBRACE:    "}",
	SEMICOLON: ";",
	COLON:     ":",

	TK_若:  "若",
	TK_则:  "则",
	TK_否则: "否则",

	ELSE:   "else",
	FOR:    "for",
	FN:     "fn",
	IF:     "if",
	RETURN: "return",
	VAR:    "var",
}

func (tt TokenType) String() string {
	s := ""
	if 0 <= tt && tt < TokenType(len(tokens)) {
		s = tokens[tt]
	}
	if s == "" {
		s = "token(" + strconv.Itoa(int(tt)) + ")"
	}
	return s
}

func SingleToken(t TokenType, val rune) Token {
	return Token{Type: t, Literal: []rune{val}}
}

func (t Token) String() string {
	typeStr := t.Type.String()
	litStr := string(t.Literal)
	if typeStr == litStr {
		return fmt.Sprintf("<%s>", typeStr)
	} else {
		return fmt.Sprintf("<%s:%s>", typeStr, litStr)
	}
}

var keywords = map[string]TokenType{
	"fn":     FN,
	"var":    VAR,
	"true":   TK_布尔,
	"false":  TK_布尔,
	"if":     IF,
	"else":   ELSE,
	"for":    FOR,
	"return": RETURN,
	"令":      TK_令,
	"为":      TK_为,
	"若":      TK_若,
	"则":      TK_则,
	"否则":     TK_否则,
}

func FindIdentType(ident string) TokenType {
	if tok, ok := keywords[ident]; ok {
		return tok
	}
	return TK_名称
}
